package com.tax.plan.utils;

import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.canvas.parser.PdfCanvasProcessor;
import com.itextpdf.kernel.pdf.canvas.parser.listener.IPdfTextLocation;
import com.itextpdf.kernel.pdf.canvas.parser.listener.RegexBasedLocationExtractionStrategy;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * pdf 文本替换
 *
 * @Author: TG
 * @Description: About this class
 * @Date :Created in 11:03 2021/5/24 0024
 * @Version : 1.0
 */
public class DefaultPdfReplaceHandler implements PdfReplaceHandler {
    /**
     * 占位符前缀
     */
    private static final String KEY_PLACEHOLDER_PREFIX = "\\$\\{";
    /**
     * 占位符后缀
     */
    private static final String KEY_PLACEHOLDER_SUFFIX = "\\}";
    /**
     * 填充数据源
     */
    private PdfReplaceDataStore pdfReplaceDataStore;
    /**
     * 替换的key映射 如：name -> ${name}
     */
    private Map<String, String> replaceKeyMap = new HashMap<>();

    /**
     * 待替换数据
     */
    private List<PdfPageReplaceItems> pdfPageReplaceItems = new ArrayList<>();


    /**
     * 填充
     *
     * @param contractTemplateIns
     * @param pdfReplaceDataStore
     * @return
     * @throws IOException
     */
    public ByteArrayOutputStream fill(InputStream contractTemplateIns, PdfReplaceDataStore pdfReplaceDataStore) throws IOException {
        this.pdfReplaceDataStore = pdfReplaceDataStore;
        //初始化替换数据源key
        initReplaceKeyMap();
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        PdfReader reader = new PdfReader(contractTemplateIns);
        try (PdfDocument pdfDocument = new PdfDocument(reader, new PdfWriter(bos));) {
            //解析替换位置
            initParseReplaceItems(pdfDocument);
            //填充
            fill0(pdfDocument);
            return bos;
        }
    }


    private void fill0(PdfDocument pdfDocument) throws IOException {
        PdfFont font = PdfFontFactory.createFont("./data/simfang.ttf", PdfEncodings.IDENTITY_H);

        for (PdfPageReplaceItems pageReplaceItem : pdfPageReplaceItems) {
            Integer pageNum = pageReplaceItem.getPageNum();
            PdfCanvas canvas = new PdfCanvas(pdfDocument.getPage(pageNum).newContentStreamAfter(), pdfDocument.getPage(pageNum).getResources(), pdfDocument);
            canvas.saveState();
            List<PdfReplaceItem> replaceItems = pageReplaceItem.getReplaceItems();
            for (PdfReplaceItem replaceItem : replaceItems) {
                canvas.setFillColor(ColorConstants.WHITE);
                //覆盖的时候y + 0.35   填充字体的时候 + 1.5 主要就是避免覆盖占位符下面的线
                canvas.rectangle(replaceItem.getX(), replaceItem.getY() + 0.35, replaceItem.getWidth(), replaceItem.getHeight());
            }
            canvas.fill();
            canvas.restoreState();

            //填充新内容
            canvas.beginText();
            for (PdfReplaceItem replaceItem : replaceItems) {
                canvas.setFontAndSize(font, replaceItem.getHeight());
                canvas.setTextMatrix(replaceItem.getX(), replaceItem.getY() + 2.0f);
                //canvas.newlineShowText(replaceItem.getValue());
                canvas.showText(replaceItem.getValue());
            }
            canvas.endText();
        }
    }


    /**
     * 初始化替换参数
     */
    private void initReplaceKeyMap() {
        if (Objects.isNull(pdfReplaceDataStore)) {
            throw new IllegalStateException("参数pdfReplaceDataStore为空");
        }
        for (String key : pdfReplaceDataStore.keys()) {
            replaceKeyMap.put(key, KEY_PLACEHOLDER_PREFIX + key + KEY_PLACEHOLDER_SUFFIX);
        }
        return;
    }

    /**
     * 解析pdf模板生成每页需要替换的数据项目,list index+1 代表页码
     *
     * @return
     */
    private void initParseReplaceItems(PdfDocument pdfDocument) throws IOException {
        PdfPageReplaceItems pageReplaceItem = null;
        for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++) {
            pageReplaceItem = new PdfPageReplaceItems(i);
            for (String key : replaceKeyMap.keySet()) {
                PdfPage page = pdfDocument.getPage(i);

                RegexBasedLocationExtractionStrategy strategy = new RegexBasedLocationExtractionStrategy(replaceKeyMap.get(key));
                PdfCanvasProcessor canvasProcessor = new PdfCanvasProcessor(strategy);
                canvasProcessor.processPageContent(page);
                Collection<IPdfTextLocation> resultantLocations = strategy.getResultantLocations();

                for (IPdfTextLocation location : resultantLocations) {
                    Rectangle rectangle = location.getRectangle();
                    PdfReplaceItem replaceItem = new PdfReplaceItem();
                    replaceItem.setPageNum(location.getPageNumber());
                    replaceItem.setX(rectangle.getX());
                    replaceItem.setY(rectangle.getY());
                    replaceItem.setWidth(rectangle.getWidth());
                    replaceItem.setHeight(rectangle.getHeight());
                    replaceItem.setKey(key);
                    replaceItem.setValue(pdfReplaceDataStore.getValue(key));
                    pageReplaceItem.add(replaceItem);
                }
            }
            pdfPageReplaceItems.add(pageReplaceItem);
        }
    }
}
